import {
  Node,
  Vec3,
  Canvas,
  UITransform,
  Widget,
  Color,
  Label,
  Scene,
  find,
  Camera,
  Layers,
} from 'cc';
import { Clock } from '../core/Clock';
import { AutoAimSystem } from '../systems/AutoAimSystem';
import { AutoFireSystem } from '../systems/AutoFireSystem';
import { AutoReloadSystem } from '../systems/AutoReloadSystem';
import { HUDController } from '../hud/HUDController';
import InputBridge from '../input/InputBridge';
import { TICK_RATES } from '../shared';
import { VisualOverlay } from '../visual/VisualOverlay';
import StateOverlay from '../debug/StateOverlay';
import EventSpy from '../debug/EventSpy';
import PlayerKinematicController from '../gameplay/PlayerKinematicController';
import PlayerAvatar from '../gameplay/PlayerAvatar';
import WeaponController from '../gameplay/WeaponController';
import CameraFollow from '../camera/CameraFollow';

function ensureCanvas(sceneRoot: Node): Node {
  let canvas = sceneRoot.getChildByName('Canvas');
  if (!canvas) {
    canvas = new Node('Canvas');
    canvas.addComponent(Canvas);
    canvas.addComponent(UITransform);
    const w = canvas.addComponent(Widget);
    w.isAlignLeft = w.isAlignRight = w.isAlignTop = w.isAlignBottom = true;
    w.left = w.right = w.top = w.bottom = 0;
    sceneRoot.addChild(canvas);
    console.debug('[INSTALL] Canvas created');
  }
  return canvas;
}

function ensurePlayer(parent: Node): Node {
  let player = parent.getChildByName('Player');
  if (!player) {
    player = new Node('Player');
    parent.addChild(player);
    console.debug('[INSTALL] Player created');
  }
  return player;
}

function ensureHud(canvas: Node): { hudNode: Node; hud: HUDController } {
  let hudNode = canvas.getChildByName('HUD');
  if (!hudNode) {
    hudNode = new Node('HUD');
    canvas.addChild(hudNode);
  }
  hudNode.addComponent(UITransform);
  const hudWidget = hudNode.getComponent(Widget) ?? hudNode.addComponent(Widget);
  hudWidget.isAlignLeft = hudWidget.isAlignRight = hudWidget.isAlignTop = hudWidget.isAlignBottom = true;
  hudWidget.left = hudWidget.right = hudWidget.top = hudWidget.bottom = 0;
  const hud = hudNode.getComponent(HUDController) ?? hudNode.addComponent(HUDController);
  return { hudNode, hud };
}

function ensureLabel(
  parent: Node,
  name: string,
  top: number,
  left: number,
  color: Color = Color.WHITE,
  initial?: string,
): Label {
  let node = parent.getChildByName(name);
  if (!node) {
    node = new Node(name);
    parent.addChild(node);
  }
  const label = node.getComponent(Label) ?? node.addComponent(Label);
  const widget = node.getComponent(Widget) ?? node.addComponent(Widget);
  widget.isAlignTop = true;
  widget.isAlignLeft = true;
  widget.top = top;
  widget.left = left;
  label.color = color;
  if (initial && !label.string) {
    label.string = initial;
  }
  return label;
}

export class SceneInstaller {
  static ensure(scene: Scene | null | undefined): Node | null {
    if (!scene) return null;
    const g = globalThis as any;
    if (g.__SCENE_INSTALL_DONE__) {
      console.log('[INSTALL] skip (already done)');
      return (g.__PLAYER_NODE__ as Node) ?? null;
    }

    try {
      const root = scene as unknown as Node;
      const canvas = ensureCanvas(root);
      canvas.getComponent(EventSpy) ?? canvas.addComponent(EventSpy);

      const player = ensurePlayer(canvas);

      // Layer defaults
      canvas.layer = Layers.Enum.UI_2D;
      root.layer = Layers.Enum.DEFAULT;
      player.layer = Layers.Enum.DEFAULT;

      const camNode = find('Canvas/Camera');
      const cam = camNode?.getComponent(Camera) ?? null;
      if (cam) {
        cam.visibility = Layers.BitMask.DEFAULT | Layers.BitMask.UI_2D;
        const pos = cam.node.worldPosition;
        player.setWorldPosition(pos.x, pos.y, 0);
        const follow = camNode.getComponent(CameraFollow) ?? camNode.addComponent(CameraFollow);
        follow.setTarget(player);
      }

      const clock = player.getComponent(Clock) ?? player.addComponent(Clock);
      const input = player.getComponent(InputBridge) ?? player.addComponent(InputBridge);
      const wc = player.getComponent(WeaponController) ?? player.addComponent(WeaponController);
      const reload = player.getComponent(AutoReloadSystem) ?? player.addComponent(AutoReloadSystem);
      const fire = player.getComponent(AutoFireSystem) ?? player.addComponent(AutoFireSystem);
      const aim = player.getComponent(AutoAimSystem) ?? player.addComponent(AutoAimSystem);

      aim.clock = clock;
      aim.autoReload = reload;
      aim.aimPivot = player;

      fire.clock = clock;
      fire.autoAim = aim;
      fire.autoReload = reload;

      let muzzle = player.getChildByName('Muzzle');
      if (!muzzle) {
        muzzle = new Node('Muzzle');
        muzzle.setWorldPosition(new Vec3(0, 1.2, 1));
        player.addChild(muzzle);
      }
      fire.muzzle = muzzle;

      (aim as any).bindClock?.(clock);
      (fire as any).bindClock?.(clock);

      const { hudNode, hud } = ensureHud(canvas);
      hud.weaponLabel = hud.weaponLabel ?? ensureLabel(hudNode, 'WeaponLabel', 10, 10, Color.WHITE, 'Weapon: -');
      hud.magazineLabel = hud.magazineLabel ?? ensureLabel(hudNode, 'MagLabel', 40, 10, Color.WHITE, 'Mag: -');
      hud.reserveLabel = hud.reserveLabel ?? ensureLabel(hudNode, 'ReserveLabel', 70, 10, Color.WHITE, 'Reserve: -');
      hud.reloadStatusLabel =
        hud.reloadStatusLabel ?? ensureLabel(hudNode, 'ReloadLabel', 100, 10, Color.WHITE, '');
      if (!hud.toastLabel) {
        const toast = hudNode.getChildByName('ToastLabel') ?? new Node('ToastLabel');
        if (!toast.parent) hudNode.addChild(toast);
        const toastLabel = toast.getComponent(Label) ?? toast.addComponent(Label);
        const toastWidget = toast.getComponent(Widget) ?? toast.addComponent(Widget);
        toastWidget.isAlignTop = true;
        toastWidget.isAlignHorizontalCenter = true;
        toastWidget.top = 10;
        hud.toastLabel = toastLabel;
      }

      (wc as any).broadcast?.();

      player.getComponent(PlayerKinematicController) ?? player.addComponent(PlayerKinematicController);
      player.getComponent(PlayerAvatar) ?? player.addComponent(PlayerAvatar);

      const debugNode = hudNode.getChildByName('DebugLabel') ?? new Node('DebugLabel');
      if (!debugNode.parent) hudNode.addChild(debugNode);
      const debugLabel = debugNode.getComponent(Label) ?? debugNode.addComponent(Label);
      const debugWidget = debugNode.getComponent(Widget) ?? debugNode.addComponent(Widget);
      debugWidget.isAlignBottom = true;
      debugWidget.isAlignLeft = true;
      debugWidget.bottom = 10;
      debugWidget.left = 10;
      debugLabel.string = 'Booting...';
      clock.register('installer-debug', TICK_RATES.stats, () => {
        const pos = player.worldPosition;
        const mv = input.snapshot().move;
        debugLabel.string = `Pos(${pos.x.toFixed(1)},${pos.y.toFixed(1)}) Move(${mv.x.toFixed(2)},${mv.y.toFixed(2)})`;
      });

      const overlay = canvas.getComponent(VisualOverlay) ?? canvas.addComponent(VisualOverlay);
      overlay.init(root, player, clock);

      const stateOverlay = canvas.getComponent(StateOverlay) ?? canvas.addComponent(StateOverlay);
      stateOverlay.setPlayer(player);

      g.__SCENE_INSTALL_DONE__ = true;
      g.__PLAYER_NODE__ = player;
      console.log('[INSTALL] W1 ensure completed');
      return player;
    } catch (err) {
      console.error('[BOOT-ERROR]', err);
      throw err;
    }
  }
}

export default SceneInstaller;
